package com.piggy.im.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.piggy.common.core.constant.BizConstants;
import com.piggy.common.core.constant.SecurityConstants;
import com.piggy.common.core.exception.base.BaseException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.PagePlus;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.satoken.utils.SecurityUtils;
import com.piggy.im.domain.SysStationMessage;
import com.piggy.im.domain.SysStationMessagePublish;
import com.piggy.im.domain.bo.SysPublishMsgBo;
import com.piggy.im.domain.bo.SysStationMessagePublishEditBo;
import com.piggy.im.domain.bo.SysStationMessagePublishQueryBo;
import com.piggy.im.domain.vo.ReceiverInfoVo;
import com.piggy.im.domain.vo.SysStationMessagePublishVo;
import com.piggy.im.enums.ReceiverType;
import com.piggy.im.server.enums.MarkEnum;
import com.piggy.im.server.mapper.SysStationMessagePublishMapper;
import com.piggy.im.server.service.ISysStationMessagePublishService;
import com.piggy.im.server.service.ISysStationMessageService;
import com.piggy.logi.sys.api.RemoteLogiDeptService;
import com.piggy.logi.sys.api.RemoteLogiRoleService;
import com.piggy.logi.sys.api.RemoteLogiUserService;
import com.piggy.logi.sys.api.domain.LogiSysRole;
import com.piggy.logi.sys.api.domain.LogiSysUser;
import com.piggy.logi.sys.api.vo.LogiSysDeptExtVo;
import com.piggy.sys.api.RemoteDeptService;
import com.piggy.sys.api.RemoteRoleService;
import com.piggy.sys.api.RemoteUserService;
import com.piggy.sys.api.domain.SysDept;
import com.piggy.sys.api.domain.SysRole;
import com.piggy.sys.api.domain.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * 站内消息发布Service业务层处理
 *
 * @author piggy
 * @date 2021-12-09
 */
@Service
@RequiredArgsConstructor
public class SysStationMessagePublishServiceImpl extends ServiceImpl<SysStationMessagePublishMapper, SysStationMessagePublish> implements ISysStationMessagePublishService {

    private final ISysStationMessageService sysStationMessageService;
//    private final RedisMessageDistributor redisMessageDistributor;

    @Resource
    private RemoteLogiRoleService remoteRoleService;

    @Resource
    private RemoteLogiUserService remoteUserService;

    @Resource
    private RemoteLogiDeptService remoteDeptService;

    @Resource
    private RemoteRoleService sysRoleService;

    @Resource
    private RemoteUserService sysUserService;

    @Resource
    private RemoteDeptService sysDeptService;


    @Override
    public SysStationMessagePublishVo queryById(Long id) {
        SysStationMessagePublishVo vo = getVoById(id, SysStationMessagePublishVo.class);
        if (ObjectUtil.isEmpty(vo)) {
            return vo;
        }
        return fillData(Lists.newArrayList(vo)).get(0);
    }

    @Override
    public TableDataInfo<SysStationMessagePublishVo> queryPageList(SysStationMessagePublishQueryBo bo) {
        PagePlus<SysStationMessagePublish, SysStationMessagePublishVo> result = pageVo(PageUtils.buildPagePlus(true), buildQueryWrapper(bo), SysStationMessagePublishVo.class);
        result.setRecordsVo(fillData(result.getRecordsVo()));
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<SysStationMessagePublishVo> queryList(SysStationMessagePublishQueryBo bo) {
        List<SysStationMessagePublishVo> voList = listVo(buildQueryWrapper(bo), SysStationMessagePublishVo.class);
        fillData(voList);
        return voList;
    }

    private LambdaQueryWrapper<SysStationMessagePublish> buildQueryWrapper(SysStationMessagePublishQueryBo bo) {
        LambdaQueryWrapper<SysStationMessagePublish> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotEmpty(bo.getId()), SysStationMessagePublish::getId, bo.getId());
        lqw.eq(bo.getMainDeptId() != null, SysStationMessagePublish::getMainDeptId, bo.getMainDeptId());
        lqw.eq(StrUtil.isNotBlank(bo.getLevel()), SysStationMessagePublish::getLevel, bo.getLevel());
        lqw.eq(bo.getStatus() != null, SysStationMessagePublish::getStatus, bo.getStatus());
        lqw.eq(StrUtil.isNotBlank(bo.getType()) && !bo.getType().equals(ReceiverType.ALL.getType()+""), SysStationMessagePublish::getType, bo.getType());
        lqw.eq(StrUtil.isNotBlank(bo.getTitle()), SysStationMessagePublish::getTitle, bo.getTitle());
        lqw.and(StrUtil.isNotBlank(bo.getReceiver()), t->t.like(SysStationMessagePublish::getReceiver, bo.getReceiver()).or().eq(SysStationMessagePublish::getReceiver, "0"));
        //lqw.like(StrUtil.isNotBlank(bo.getReceiver()), SysStationMessagePublish::getReceiver, bo.getReceiver());
        lqw.eq(StrUtil.isNotBlank(bo.getDescription()), SysStationMessagePublish::getDescription, bo.getDescription());
        lqw.eq(StrUtil.isNotBlank(bo.getState()), SysStationMessagePublish::getState, bo.getState());
        lqw.in(!CollectionUtil.isEmpty(bo.getMsgType()), SysStationMessagePublish::getMsgType, bo.getMsgType());
        //lqw.orderByDesc(SysStationMessagePublish::getCreateTime);
        return lqw;
    }

    private List<SysStationMessagePublishVo> fillData(List<SysStationMessagePublishVo> voList) {
        // 这理需要查询服务商
        Long mainDeptId = 0L;
        if (CollUtil.isNotEmpty(voList)) {
            mainDeptId = ObjectUtil.defaultIfNull(voList.get(0).getMainDeptId(), 0L);
        }
        List<LogiSysUser> userList = remoteUserService.queryUserAll(mainDeptId, SecurityConstants.INNER).getData();
        List<SysUser> sysUserList = sysUserService.queryUserAll(SecurityConstants.INNER).getData();
        Map<Long, SysUser> sysUserMap = sysUserList.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
        Map<Long, LogiSysUser> userMap = userList.stream().collect(Collectors.toMap(LogiSysUser::getUserId, Function.identity()));

        List<LogiSysRole> roleList = remoteRoleService.queryRoleAll(mainDeptId, SecurityConstants.INNER).getData();
        List<SysRole> sysRoleList = sysRoleService.queryRoleAll(SecurityConstants.INNER).getData();
        Map<Long, SysRole> sysRoleMap = sysRoleList.stream().collect(Collectors.toMap(SysRole::getRoleId, Function.identity()));
        Map<Long, LogiSysRole> roleMap = roleList.stream().collect(Collectors.toMap(LogiSysRole::getRoleId, Function.identity()));

        List<LogiSysDeptExtVo> deptList = remoteDeptService.queryDeptAll(SecurityConstants.INNER).getData();
        List<SysDept> sysDeptList = sysDeptService.queryDeptAll(SecurityConstants.INNER).getData();
        Map<Long, SysDept> sysDeptMap = sysDeptList.stream().collect(Collectors.toMap(SysDept::getDeptId, Function.identity()));
        Map<Long, LogiSysDeptExtVo> deptMap = deptList.stream().collect(Collectors.toMap(LogiSysDeptExtVo::getDeptId, Function.identity()));

        voList.stream().peek(vo-> {

            final ReceiverType type = ReceiverType.of(Integer.valueOf(vo.getType()));
            if (ObjectUtil.isEmpty(type)) {
                return;
            }

            if (ReceiverType.ALL.eq(type)) {
                vo.setReceiver("-1");
                return;
            }

            final List<Long> receiver = Arrays.stream(vo.getReceiver().split(",")).mapToLong(Long::parseLong).boxed().collect(toList());
            // 发送目标
            List<String> receivers = new ArrayList<>();
            if (ReceiverType.USER.eq(type)) {
                if (CollUtil.isNotEmpty(receiver)) {
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
                        receivers = receiver.stream().map(t->StrUtil.blankToDefault(ObjectUtil.defaultIfNull(sysUserMap.get(t), new SysUser()).getUserName(), "")).collect(toList());
                    }
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.LOGI)) {
                        receivers = receiver.stream().map(t->StrUtil.blankToDefault(ObjectUtil.defaultIfNull(userMap.get(t), new LogiSysUser()).getPhonenumber(), "")).collect(toList());
                    }
                }
            } else if (ReceiverType.ROLE.eq(type)) {
                if (CollUtil.isNotEmpty(receiver)) {
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
                        receivers = receiver.stream().map(t->StrUtil.blankToDefault(ObjectUtil.defaultIfNull(sysRoleMap.get(t), new SysRole()).getRoleName(), "")).collect(toList());
                    }
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.LOGI)) {
                        receivers = receiver.stream().map(t->StrUtil.blankToDefault(ObjectUtil.defaultIfNull(roleMap.get(t), new LogiSysRole()).getRoleName(), "")).collect(toList());
                    }
                }
            } else if (ReceiverType.COMPANY.eq(type)) {
                if (CollUtil.isNotEmpty(receiver)) {
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
                        receivers = receiver.stream().map(t-> StrUtil.blankToDefault(ObjectUtil.defaultIfNull(sysDeptMap.get(t),new SysDept()).getDeptName(),"")).collect(toList());
                    }
                    if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.LOGI)) {
                        receivers = receiver.stream().map(t-> StrUtil.blankToDefault(ObjectUtil.defaultIfNull(deptMap.get(t),new LogiSysDeptExtVo()).getDeptName(),"")).collect(toList());
                    }
                }
            }
            if (CollUtil.isNotEmpty(receivers)) {
                vo.setReceiverName(String.join(",", receivers));
            }
        }).collect(toList());

        return voList;
    }

    @Override
    public Boolean insertByAddBo(SysStationMessagePublishEditBo bo) {
        SysStationMessagePublish add = BeanUtil.toBean(bo, SysStationMessagePublish.class);
        if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
            add.setCreateBy(SecurityUtils.getUsername());
        }
        if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.LOGI)) {
            add.setCreateBy(SecurityUtils.getPhone());
        }
        add.setCreateTime(new Date());
        add.setMainDeptId(SecurityUtils.getMainDeptId());
        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    public Boolean updateByEditBo(SysStationMessagePublishEditBo bo) {
        SysStationMessagePublish update = BeanUtil.toBean(bo, SysStationMessagePublish.class);
        if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
            update.setCreateBy(SecurityUtils.getUsername());
        }
        if (SecurityUtils.getOauthUser().getBiz().equals(BizConstants.BOSS)) {
            update.setUpdateBy(SecurityUtils.getPhone());
        }
        update.setUpdateBy(SecurityUtils.getPhone());
        update.setUpdateTime(new Date());
        update.setMainDeptId(SecurityUtils.getMainDeptId());
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(SysStationMessagePublish entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        //TODO 做一些业务上的校验,判断是否需要校验
        return removeByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publish(Long id) {
        final SysStationMessagePublish messagePublish = Optional.ofNullable(this.baseMapper.selectById(id)).orElseThrow(() -> new BaseException("需要发布的消息不存在"));
        final List<Long> receiver = Optional.of(Arrays.stream(messagePublish.getReceiver().split(",")).mapToLong(Long::parseLong).boxed().collect(toList()))
                .orElseThrow(() -> new BaseException("接受者不能为空"));
        SysStationMessagePublish record = new SysStationMessagePublish();
        record.setId(id);
        record.setStatus(1);
        this.baseMapper.updateById(record);
        final ReceiverType type = ReceiverType.of(Integer.parseInt(messagePublish.getType()));
        // 发送目标
        if (ReceiverType.USER.eq(type) || ReceiverType.ALL.eq(type)) {
            messagePublish.setType(type.getType().toString());
            publish(messagePublish, receiver);
            if (messagePublish.getSyncLogi()==1) {
                SysStationMessagePublish logiPush = BeanUtil.toBean(messagePublish,SysStationMessagePublish.class);
                logiPush.setType(ReceiverType.ALL.getType()+"");
                logiPush.setBizSys(BizConstants.LOGI);
                logiPush.setReceiver("-1");
                publish(logiPush, receiver);
            }
        } else if (ReceiverType.ROLE.eq(type)) {
            //根据角色推送消息
            messagePublish.setType(ReceiverType.ROLE.getType().toString());
            publishByRoleList(messagePublish, receiver);
            if (messagePublish.getSyncLogi()==1) {
                SysStationMessagePublish logiPush = BeanUtil.toBean(messagePublish,SysStationMessagePublish.class);
                logiPush.setType(ReceiverType.ALL.getType()+"");
                logiPush.setBizSys(BizConstants.LOGI);
                logiPush.setReceiver("-1");
                publish(logiPush, receiver);
            }
        } else if (ReceiverType.SCENE.eq(type)) {
            //根据场景推送消息
            //publishBySceneList(messagePublish, receiver);
            //TODO;
        } else if (ReceiverType.COMPANY.eq(type)) {
            //根据部门推送消息
            messagePublish.setType(ReceiverType.COMPANY.getType().toString());
            publishByDeptList(messagePublish, receiver);
            if (messagePublish.getSyncLogi()==1) {
                SysStationMessagePublish logiPush = BeanUtil.toBean(messagePublish,SysStationMessagePublish.class);
                logiPush.setType(ReceiverType.ALL.getType()+"");
                logiPush.setBizSys(BizConstants.LOGI);
                logiPush.setReceiver("-1");
                publish(logiPush, receiver);
            }
        }
        else if (ReceiverType.ALL.eq(type)) {
            //根据部门推送消息
            messagePublish.setType(ReceiverType.ALL.getType().toString());
            publishByDeptList(messagePublish, receiver);
            if (messagePublish.getSyncLogi()==1) {
                SysStationMessagePublish logiPush = BeanUtil.toBean(messagePublish,SysStationMessagePublish.class);
                logiPush.setType(ReceiverType.ALL.getType()+"");
                logiPush.setBizSys(BizConstants.LOGI);
                logiPush.setReceiver("-1");
                publish(logiPush, receiver);
            }
        }
    }

    @Override
    public List<ReceiverInfoVo> getMessageReceiveList(String receiverType, Long mainDeptId) {
        List<ReceiverInfoVo> result = new ArrayList<>();
        Long mainDept = ObjectUtil.defaultIfNull(mainDeptId, 0L);
        final ReceiverType type = ReceiverType.of(Integer.valueOf(receiverType));
        if (ReceiverType.USER.eq(type)) {
            List<LogiSysUser> userList = remoteUserService.queryUserAll(mainDept,SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(userList)) {
                result = userList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getUserId());
                    vo.setName(s.getUserName());
                    return vo;
                }).collect(Collectors.toList());
            }
        } else if (ReceiverType.ROLE.eq(type)) {
            List<LogiSysRole> roleList = remoteRoleService.queryRoleAll(mainDept, SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(roleList)) {
                result = roleList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getRoleId());
                    vo.setName(s.getRoleName());
                    return vo;
                }).collect(Collectors.toList());
            }
        } else if (ReceiverType.SCENE.eq(type)) {
            //TODO
        } else if (ReceiverType.COMPANY.eq(type)) {
            List<LogiSysDeptExtVo> deptList = remoteDeptService.queryDeptAll(SecurityConstants.INNER).getData();
            if (!CollectionUtil.isEmpty(deptList)) {
                result = deptList.stream().map(s -> {
                    ReceiverInfoVo vo = new ReceiverInfoVo();
                    vo.setId(s.getDeptId());
                    vo.setName(s.getDeptName());
                    return vo;
                }).collect(Collectors.toList());
            }
        }
        return result;
    }

    @Override
    public void publishMsg(SysPublishMsgBo sysPublishMsgBo) {
        if (ObjectUtil.isEmpty(sysPublishMsgBo)) {
            throw new BaseException("消息不能为空");
        }

        if (CollectionUtil.isEmpty(sysPublishMsgBo.getUserIdList())) {
            throw new BaseException("发送的用户列表不能为空");
        }

        SysStationMessagePublish messagePublish = BeanUtil.toBean(sysPublishMsgBo, SysStationMessagePublish.class);
        //websocket推送消息
        publish(messagePublish, sysPublishMsgBo.getUserIdList());
    }

    void publish(SysStationMessagePublish messagePublish, List<Long> idList) {
        for (Long id : idList) {
            SysStationMessage message = new SysStationMessage();
            message.setTitle(messagePublish.getTitle());
            message.setContent(messagePublish.getContent());
            message.setDescription(messagePublish.getDescription());
            message.setLevel(messagePublish.getLevel());
            message.setReceiveId(0L);
            message.setRoleId(0L);
            message.setDeptId(0L);
            message.setBizSys(messagePublish.getBizSys());
            message.setMainDeptId(messagePublish.getMainDeptId());
            message.setCreateTime(new Date());
            message.setMsgType(messagePublish.getMsgType());
            if (messagePublish.getType().equalsIgnoreCase(ReceiverType.USER.getType()+"") ||
                    messagePublish.getType().equalsIgnoreCase(ReceiverType.ALL.getType()+"")) {
                message.setReceiveId(id);
            }
            if (messagePublish.getType().equalsIgnoreCase(ReceiverType.ROLE.getType()+"")) {
                message.setRoleId(id);
            }
            if (messagePublish.getType().equalsIgnoreCase(ReceiverType.COMPANY.getType()+"")) {
                message.setDeptId(id);
            }
            message.setCreateTime(new Date());
            sysStationMessageService.save(message);

/*
            // websocket 发送消息
            MessageDO messageDO = new MessageDO();
            messageDO.setNeedBroadcast(Boolean.FALSE);
            messageDO.setSessionKeys(Collections.singletonList(userId));
            messageDO.setMessageText(JSONUtil.toJsonStr(message));
            redisMessageDistributor.distribute(messageDO);*/
        }
    }

    /**
     * 根据角色推送消息
     *
     * @param messagePublish
     * @param roleList
     */
    private void publishByRoleList(SysStationMessagePublish messagePublish, List<Long> roleList) {
        //1.根据角色列表获取用户id列表
        /*List<SysUser> userList = remoteRoleService.getRoleUserByRoleIds(roleList, SecurityConstants.INNER).getData();
        List<Long> userIdList = userList.stream()
                .filter(i -> UserStatus.OK.getCode().equals(i.getStatus()))
                .map(SysUser::getUserId).collect(Collectors.toList());*/
        //2.websocket推送消息
        publish(messagePublish, roleList);
    }

    /**
     * 根据部门推送消息
     *
     * @param messagePublish
     * @param deptList
     */
    private void publishByDeptList(SysStationMessagePublish messagePublish, List<Long> deptList) {

/*        List<SysUser> userList = remoteUserService.getUserByDeptIds(deptList, SecurityConstants.INNER).getData();
        List<Long> userIdList = userList.stream()
                .filter(i -> UserStatus.OK.getCode().equals(i.getStatus()))
                .map(SysUser::getUserId).collect(Collectors.toList());*/
        //2.websocket推送消息
        publish(messagePublish, deptList);
    }
}
